package org.su.generalmvc.core;


import org.su.generalmvc.IParamBinder;
import org.su.generalmvc.bind.DefaultParamBinder;
import org.su.generalmvc.config.BeanMapping;
import org.su.generalmvc.config.PackageContext;
import org.su.generalmvc.config.XSSHConfig;
import org.su.generalmvc.scanner.ActionScanner;
import org.su.generalmvc.scanner.IPreprocessor;
import org.su.generalmvc.scanner.XMLConfigLoader;
import org.su.generalmvc.util.ClassUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


import java.io.File;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 初始化应用环境
 * 
 * @author yangchuan
 * 
 */
public class InitialContext {

	private static final InitialContext instance = new InitialContext();
	protected static final Log logger = LogFactory.getLog(InitialContext.class);

	private IXsshApplicationContext context;
	
	/**
	 * 标示环境是否加载成功
	 */
	private boolean loadSuccess = false;

	public boolean isLoadSuccess() {
		return loadSuccess;
	}

	private InitialContext() {

	}

	public static InitialContext getInstance() {
		return instance;
	}

	/**
	 * 初始化应用环境上下文
	 * 
	 * @param configPath
	 * @throws Exception
	 */
	public void init(String configPath,IServiceContext serviceContext) throws Exception {
        URL url = InitialContext.class.getResource("/");
        File file = new File(url.toURI());
		String path = file.getAbsolutePath();
		XMLConfigLoader xmlLoder = new XMLConfigLoader();

		XSSHConfig xsshConfig = xmlLoder.loadXmlConfig(path+"/"+XSSHConfig.getConfigPath(configPath,true));
		
		List<String> includes = xsshConfig.getIncludes();
		if(includes != null){
			XSSHConfig config = null;
			for(String cfp : includes){
				logger.debug("loading "+cfp);
				config = xmlLoder.loadXmlConfig(path+XSSHConfig.getConfigPath(cfp,false));
				xsshConfig.copy(config);
			}
		}
		

		if (xsshConfig.isUseSpring()) {
			context = new SpringApplicationContext();
		} else {
			context = new DefaultApplicationContext();
		}
		context.init(serviceContext);
		Map<String, XsshPackage> _packages = new HashMap<String, XsshPackage>();
		parseConfig(xsshConfig, _packages);
		
		int serverId = lookup(new javax.naming.InitialContext(),"java:/comp/env/serverId",xsshConfig.getServerId());
		context.setServerId(serverId);

		//initVelocityEngine(xsshConfig, servletContext);

		initDataSource(xsshConfig);

        IParamBinder paramBinder = null;
        if(xsshConfig.getParamBinder() == null) {
            paramBinder = new DefaultParamBinder();
        }
        context.addBean(xsshConfig.getContextPrefix() +":"+ IParamBinder.class.getName(), Class.forName(xsshConfig.getParamBinder()));


        preprocess(xsshConfig.getPreprocessors());

		String classRoot = xsshConfig.getScannerPackage();
		if(classRoot==null){
			classRoot = "";
		}

        if(xsshConfig.getAfterAcoinScaned() != null){
			context.addBean("afterAcoinScaned", Class.forName(xsshConfig.getAfterAcoinScaned()));
		}
		
		new ActionScanner(context).publishActions(classRoot, _packages);

		LifeCycleManager.getInstence().init(serviceContext);
		
		loadSuccess = true;
		

	}

	/**
	 * 预处理环境加载器
	 * 
	 * @param preprocessors
	 */

	private void preprocess(List<BeanMapping> preprocessors) throws Exception {
		if (preprocessors != null && preprocessors.size() > 0) {

			for (BeanMapping p : preprocessors) {
				String clazz = p.getClazz();
				IPreprocessor preprocessor = (IPreprocessor) Class.forName(
                        clazz).newInstance();
				preprocessor.process();
				logger.info("found preprocessor: " + clazz + "");
			}
		} else {
			logger.debug("no Specified preprocessor invoked.");
		}
	}

	/**
	 * 初始化系统数据库
	 * 
	 * @param config
	 */
	private void initDataSource(XSSHConfig config) throws Exception {
		/*if (config.isUseDB()) {
			try {
				logger.info("***********init DAO Context start*************");
				DaoFactory.init();
				logger.info("***********DAO Context init end*************");
			} catch (NamingException e) {
				throw new ServletException(e);
			}
		} else {
			logger.info("***********system not use dao *************");
		}*/
	}

	public IXsshApplicationContext getContext() {
		return context;
	}

	public void setContext(IXsshApplicationContext context) {
		this.context = context;
	}

	private URL getURL(String path) {
		ClassLoader classLoader = ClassUtils.getDefaultClassLoader();

		URL resourceUrl = classLoader.getResource(path);
		return resourceUrl;
	}

	/**
	 * 处理配置，将配置信息封装到XsshPackage中
	 * 
	 * @param xsshConfig
	 * @throws NoSuchMethodException
	 * @throws SecurityException
	 */
	private void parseConfig(XSSHConfig xsshConfig,
			Map<String, XsshPackage> _packages) throws SecurityException,
            NoSuchMethodException {
		context.setConfig(xsshConfig);
		PackageContext pcontext = new PackageContext();
		pcontext.setContext(context);
        pcontext.parseConfig(_packages)	;
        parseResultType();
	}

	
	/**
	 * 解析结果类型处理器
	 */
	private void parseResultType() {
		List<BeanMapping> rts = context.getConfig().getResultTypes().getResultType();
		for (BeanMapping rt : rts) {
			context.addBean(rt.getName(), rt.getClazz());
			logger.info("found resultType: " + rt.getClazz() + "");
		}
	}
	
	/**
	 * 从名称目录中获取机器id
	 * @param initialContext
	 * @param name
	 * @param defualtValue
	 * @return
	 */
	private int lookup(javax.naming.InitialContext initialContext,String name,int defualtValue) {
		Object obj = null;
		int value;
		try{
			obj = initialContext.lookup(name);
		}catch (Exception e) {
			obj = null;
			logger.error(e);
		}
		if(obj==null || "".equals(obj)){
			value = defualtValue;
		}else{
			value = Integer.valueOf(obj + "");
		}
		return value;
	}

}
